home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1996 February / macformat-034.iso / mac / Shareware City / Developers / simple-sockets-11-c / Simple Sockets 1.1 ƒ / ip ƒ / iplow.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-28  |  20.8 KB  |  961 lines  |  [TEXT/CWIE]

  1. /*
  2.  * iplow.c
  3.  *
  4.  * Low routines for MacTCP.  This file contains the code that talks
  5.  * directly to the MacTCP driver.  I hope that when Apple changes
  6.  * the IP interface around in system 8, this will be the only file
  7.  * that requires modification.
  8.  *
  9.  * This should vaguely approximate socket_like calls. Only asynch-
  10.  * ronous calls will be used.
  11.  *
  12.  * This library was strongly patterned after NewsWatcher, with the
  13.  * blessing of John Norstad.
  14.  *
  15.  * Mike Trent 8/94
  16.  *
  17.  */
  18. /* 11/27/95 - Added Universal Headers check.
  19.  */
  20.  
  21. /* ANSI Includes */
  22. #include <string.h> 
  23.  
  24. /* Additional Mac Includes */
  25.  
  26. // Determine if we are using universal headers.. 
  27. #ifdef UNIVERSAL_INTERFACES_VERSION
  28.     #define __UNIVERSAL_HEADERS__
  29. #endif
  30.  
  31. #include <MacTCPCommonTypes.h>
  32. #include <AddressXlation.h>
  33. #include <MiscIPPB.h>
  34. #include <UDPPB.h>
  35. #include <TCPPB.h>
  36. #include <GetMyIPAddr.h>
  37.  
  38. /* Local Includes */
  39.  
  40. #include "ip.h"
  41. #include "iplow.h"
  42. #include "butil.h"
  43.  
  44. /* constants for this module */
  45.  
  46. #define kBufferLength 32767             /*  32 k  */
  47. //#define kBufferLength 65535            /* unsigned short */
  48.  
  49. /* Global to this Module */
  50.  
  51. static short gRefNum;   /* refnum for talking to MacTCP */
  52. Spin gSpin;                /* chosen spin routine */
  53.  
  54. /* Private Function headers */
  55.  
  56. pascal void myResultProc (hostInfo *hi, char *data);    /*private*/
  57. pascal void MyTCPNotifyProc(StreamPtr stream, unsigned short eventCode, Ptr data, 
  58.                             unsigned short termr, struct ICMPReport *icmpMsg);
  59. pascal void MyUDPNotifyProc(StreamPtr stream, unsigned short eventCode, Ptr data, 
  60.                             struct ICMPReport *icmpMsg);
  61. OSErr SpinDefault (void);
  62. void InitUDPPB (UDPiopb *pb);
  63.  
  64.  
  65.  
  66. /**
  67.  **
  68.  **  GENERIC MacTCP ROUTINES
  69.  **
  70.  **/
  71.  
  72.  
  73. /* LowInitMacTCP 
  74.  * - Inits the MacTCP driver. It should be called once near the 
  75.  *     beginning of the program. 
  76.  * Returns OSErr: from OpenDriver
  77.  */
  78.  
  79. OSErr LowInitMacTCP (void)
  80. {
  81.     OSErr    err;
  82.     
  83.     err = OpenDriver("\p.IPP",&gRefNum);
  84.     return(err);
  85. }
  86.  
  87. void LowSetSpin(Spin spinRoutine)
  88. {
  89.     if (spinRoutine == nil)
  90.         gSpin = SpinDefault;
  91.     else
  92.         gSpin = spinRoutine;
  93. }
  94.  
  95. /* LowSpin
  96.  * - Invokes Spin Routine
  97.  */
  98. void LowSpin(void)
  99. {
  100.     (void)(*gSpin)();
  101. }
  102.  
  103. /* SpinDefault
  104.  * - a routine that handles events while waiting for a connection or
  105.  *   somesuch.  Currently, it should just call some event routine
  106.  *   so that other processes can function properly.
  107.  *
  108.  *     Strongly patterned after GiveTime() in NewsWatcher.
  109.  */
  110.  
  111. OSErr SpinDefault (void)
  112. {
  113.     EventRecord ev;
  114.     Boolean gotEvt;
  115.     short part;
  116.     WindowPtr theWindow;
  117.  
  118.     gotEvt = WaitNextEvent(everyEvent,&ev,0,nil);
  119.     if ( gotEvt )
  120.         switch (ev.what) {
  121.             case mouseDown:
  122.                 part = FindWindow(ev.where, &theWindow);
  123.                 if (part == inSysWindow) 
  124.                     SystemClick(&ev, theWindow);
  125.                 break;
  126.             case activateEvt:
  127.                 break;
  128.             case updateEvt:
  129.                 break;
  130.             case app4Evt:
  131.                 break;
  132.             case keyDown:
  133.             case autoKey:
  134.                 if ((ev.message & charCodeMask) == 0x1B) {
  135.                     return -1;
  136.                 }
  137.                 break;
  138.         }
  139.     return 0;
  140. }
  141.  
  142.  
  143. /* LowStringToAddr
  144.  * - Performs a DNS lookup for the host 'name'.
  145.  *        *name  - the name of the host. This can be in DNS name form
  146.  *                 or in "dot notation". The "official" name of the
  147.  *                 host will be returned.
  148.  *        *ipNum - returned ip number.
  149.  * Returns OSErr: StrToAddr call.
  150.  */
  151.  
  152. OSErr LowStringToAddr(char *name, unsigned long *ipNum)
  153. {
  154.     hostInfo hi;
  155.     char done = 0x00;
  156.     OSErr err;
  157. #ifdef __UNIVERSAL_HEADERS__
  158.     ResultUPP myResultUPP;
  159. #endif 
  160.  
  161.     if ((err = OpenResolver(nil)) != noErr)    
  162.         return err;
  163.  
  164. #ifdef __UNIVERSAL_HEADERS__
  165.     myResultUPP = NewResultProc(myResultProc);
  166.  
  167.     err = StrToAddr(name, &hi, myResultUPP, &done) ;
  168. #else
  169.     err = StrToAddr(name, &hi, myResultProc, &done);
  170. #endif // __UNIVERSAL_HEADERS__
  171.  
  172.     if (err == cacheFault) {
  173.         while (!done) 
  174.             if ((*gSpin)()){
  175.                 err = 1;
  176.                 goto foo;
  177.             }
  178.     } else if (err != noErr) goto foo;
  179.     
  180.     if ((hi.rtnCode == noErr) || (hi.rtnCode == cacheFault)) {
  181.         *ipNum = hi.addr[0];
  182.         strcpy(name, hi.cname);
  183.         name[strlen(name) -1] = '\0';
  184.     }
  185.     err = hi.rtnCode;
  186.         
  187. foo:
  188.     (void) CloseResolver();
  189.  
  190. #ifdef __UNIVERSAL_HEADERS__
  191.     DisposeRoutineDescriptor(myResultUPP);
  192. #endif // __UNIVERSAL_HEADERS__
  193.  
  194.     return err;
  195. }
  196.  
  197. /* LowAddrToName
  198.  * - Provided an ipNum, LowAddrToName will look up the DNS name for
  199.  *   that address; if said name exists.
  200.  *        ipNum - ip address.
  201.  *        *name - returned DNS name.
  202.  * Returns OSErr: AddrToName call
  203.  */
  204.  
  205. OSErr LowAddrToName(unsigned long ipNum, char *name)
  206. {    
  207.     hostInfo hi;
  208.     char done = 0x00;
  209.     OSErr err;
  210. #ifdef __UNIVERSAL_HEADERS__
  211.     ResultUPP myResultUPP;
  212. #endif 
  213.  
  214.     if ((err = OpenResolver(nil)) != noErr)    
  215.         return err;
  216.  
  217. #ifdef __UNIVERSAL_HEADERS__
  218.     myResultUPP = NewResultProc(myResultProc);
  219.  
  220.     err = AddrToName(ipNum, &hi, myResultUPP, &done);
  221. #else
  222.     err = AddrToName(ipNum, &hi, myResultProc, &done);
  223. #endif // __UNIVERSAL_HEADERS__
  224.  
  225.     if (err == cacheFault) {
  226.         while(!done) 
  227.             if ((*gSpin)()) {
  228.                 err = 1;
  229.                 goto foo;
  230.             }
  231.  
  232.     } else if (err != noErr) goto foo;
  233.     
  234.     if ((hi.rtnCode == noErr) || (hi.rtnCode == cacheFault)) {
  235.         strcpy(name, hi.cname);
  236.         name[strlen(name)-1] = '\0';
  237.         err = noErr;
  238.     } else  err = hi.rtnCode;
  239.     
  240. foo:
  241.     (void) CloseResolver();
  242.  
  243. #ifdef __UNIVERSAL_HEADERS__
  244.     DisposeRoutineDescriptor(myResultUPP);
  245. #endif // __UNIVERSAL_HEADERS__
  246.  
  247.     return err;
  248. }
  249.  
  250.  
  251. /* myResultProc
  252.  * - ProcPtr (UPP) called when DNS routines cacheFault.
  253.  *   See MacTCP Dev Kit.
  254.  *         *hi   - hostInfo record returned by driver.
  255.  *        *data - user pointer ... used to flag when data is
  256.  *                valid.
  257.  */ 
  258.  
  259. pascal void myResultProc(hostInfo *hi, char *data)
  260. {
  261. #pragma unused (hi)
  262.     *data = 0xff;
  263. }
  264.  
  265.  
  266. /* LowGetMyIP
  267.  * - Returns local machines IP Number.
  268.  *        *ipNum - returned IP Number
  269.  * Returns OSErr: PBControl
  270.  */
  271.  
  272. OSErr LowGetMyIP (unsigned long *ipNum)
  273. {
  274.     OSErr err;
  275.     struct GetAddrParamBlock ippb;
  276.     
  277.     bzero ((char *)&ippb, sizeof(struct GetAddrParamBlock));
  278.  
  279.     ippb.csCode = ipctlGetAddr;
  280.     ippb.ioCRefNum = gRefNum;
  281.     
  282.     err = PBControl((ParmBlkPtr)&ippb, true);
  283.     if (err != noErr) return err;
  284.     
  285.     while (ippb.ioResult > 0) 
  286.         if ((*gSpin)())
  287.             return 1;
  288.  
  289.     if ((err = ippb.ioResult) != noErr) return err;
  290.     
  291.     *ipNum = ippb.ourAddress;
  292.     
  293.     return err;
  294. }
  295.  
  296.  
  297. /**
  298.  **
  299.  **  UDP/IP MacTCP ROUTINES
  300.  **
  301.  **/
  302.  
  303. /* As of 4/10/95, these routines have not been rigorously tested. /*
  304.  
  305. /* InitUDPPB
  306.  * - A utility routine to zero a UDPiopb structure, and set some
  307.  *     global initializations.
  308.  *        *pb - UDPiopb to be initialized
  309.  */
  310.  
  311. void InitUDPPB (UDPiopb *pb)
  312. {
  313.     bzero ((char *)pb, sizeof(UDPiopb));
  314.     pb->ioResult = 1;
  315.     pb->ioCRefNum = gRefNum;
  316. }
  317.  
  318. /* LowUDPCreate
  319.  * - Creates UDP stream asynchronously.
  320.  *     *stream - returns the UDP stream pointer.
  321.  *       *port   - port number requested, 0 = any. If *port = 0, the port assigned
  322.  *                 will be returned in *port.  If port = nil, any port will be used,
  323.  *                 but nothing will be returned (read: no bus error).
  324.  *       *sockets- this is ip.c specific - an unfortunate kludge.
  325.  * Returns OSErr: MemErr or PBControl
  326.  */
  327.  
  328. OSErr LowUDPCreate (StreamPtr *stream, unsigned short *port, mac_socket *sockets)
  329. {
  330.     UDPiopb pb;
  331.     OSErr err = noErr;
  332.     Ptr buffer;
  333. #ifdef __UNIVERSAL_HEADERS__
  334.     // here's a minor memory leak. If this socket is disposed, the notifyUPP won't
  335.     // be disposed.
  336.     UDPNotifyUPP notifyUPP = NewUDPNotifyProc(MyUDPNotifyProc);
  337. #endif // __UNIVERSAL_HEADERS__
  338.  
  339.     buffer = NewPtr(kBufferLength);
  340.     if ((err = MemError()) != noErr) {
  341.         return (err);
  342.     }
  343.     
  344.     InitUDPPB(&pb);
  345.     
  346.     pb.csCode = UDPCreate;
  347.     pb.csParam.create.rcvBuff = buffer;
  348.     pb.csParam.create.rcvBuffLen = kBufferLength;
  349. #ifdef __UNIVERSAL_HEADERS__
  350.     pb.csParam.create.notifyProc = notifyUPP;
  351. #else
  352.     pb.csParam.create.notifyProc = MyUDPNotifyProc;
  353. #endif // __UNIVERSAL_HEADERS__
  354.     pb.csParam.create.localPort = (port != nil) ? *port: 0;
  355.     pb.csParam.create.userDataPtr = (Ptr)sockets;
  356.     
  357.     err = PBControl((ParmBlkPtr)&pb,true);
  358.     while (pb.ioResult > 0) (*gSpin)();
  359.  
  360.     *stream = pb.udpStream;
  361.     if ((port != nil) && (*port == 0)) *port = pb.csParam.create.localPort;
  362.     err = pb.ioResult;
  363.  
  364.     return err;
  365. }
  366.  
  367. /* LowUDPRead
  368.  * - reads from a UDP stream.
  369.  *     stream      - the UDP stream ptr;
  370.  *     timeout     - the number of seconds MacTCP should wait before timing out; 
  371.  *                     0 = no timeout;
  372.  *       buf         - a pointer to memory for output to be written into;
  373.  *       *buflen     - the size of the memory pointed to by buf.  When LowUDPRead
  374.  *                     returns, *buflen stores the number of bytes actually read;
  375.  *       *remoteHost - IP number of the host to read from.  If *remoteHost = 0,
  376.  *                     then any host will be accepted, and their ip number will
  377.  *                     be stored in *remoteHost upon completion;
  378.  *       *remotePort - like *remoteHost above.
  379.  * Returns OSErr:  PBControl or ioResult.
  380.  */
  381.  
  382. OSErr LowUDPRead (StreamPtr stream, char timeout, Ptr buf, int *buflen, 
  383.                     unsigned long *remoteHost, unsigned short *remotePort)
  384. {
  385.     UDPiopb pb;
  386.     OSErr err = noErr;
  387.  
  388.     InitUDPPB(&pb);
  389.     
  390.     pb.csCode = UDPRead;
  391.     pb.udpStream = stream;
  392.     pb.csParam.receive.timeOut = timeout;
  393.     
  394.     if ((err = PBControl((ParmBlkPtr)&pb,true)) != noErr)
  395.         return err;
  396.     
  397.     while (pb.ioResult > 0) 
  398.         if ((*gSpin)())
  399.             return 1;
  400.  
  401.     
  402.     *buflen = pb.csParam.receive.rcvBuffLen;
  403.     bcopy ((char *)pb.csParam.receive.rcvBuff, (char *)buf, (long)*buflen);
  404.     *remoteHost = pb.csParam.receive.remoteHost;
  405.     *remotePort = pb.csParam.receive.remotePort;
  406.     
  407.     err = pb.ioResult;
  408.     
  409.     pb.csCode = UDPBfrReturn;                // Instead of returning right away,
  410.     pb.ioResult = 1;                        // we need to return the buffer ptr
  411.     (void)PBControl((ParmBlkPtr)&pb, true);    // to the driver.
  412.     while (pb.ioResult>0)
  413.         if ((*gSpin)())
  414.             return 1;
  415.     
  416.     return err;
  417. }
  418.  
  419. /* LowUDPWrite
  420.  * Writes Data to a UDP stream.
  421.  *    stream     - the UDP stream ptr;
  422.  *      wdsPtr     - a wdsPtr: see MacTCP Developer's Kit;
  423.  *      remoteHost - IP number of remote host to write to;
  424.  *      remotePort - port number to write to.
  425.  * Returns OSErr: PBControl or ioResult.
  426.  */
  427.  
  428. OSErr LowUDPWrite (StreamPtr stream, Ptr wdsPtr, unsigned long remoteHost, 
  429.                     unsigned short remotePort)
  430. {
  431.     UDPiopb pb;
  432.     OSErr err = noErr;
  433.  
  434.     InitUDPPB(&pb);
  435.     
  436.     pb.csCode = UDPWrite;
  437.     pb.udpStream = stream;
  438.     pb.csParam.send.remoteHost = remoteHost;
  439.     pb.csParam.send.remotePort = remotePort;
  440.     pb.csParam.send.wdsPtr = wdsPtr;
  441.     pb.csParam.send.checkSum = 0; /* MDT FIX */
  442.     
  443.     if ((err = PBControl((ParmBlkPtr)&pb,true)) != noErr)
  444.         return err;
  445.     
  446.     while (pb.ioResult > 0) 
  447.         if ((*gSpin)())
  448.             return 1;
  449.     return pb.ioResult;
  450. }
  451.  
  452. /* LowUDPRelease
  453.  * Releases memory for a UDP stream. This must be called when a stream is 
  454.  * no longer needed.
  455.  *    stream - the UDP stream ptr.
  456.  * Returns OSErr: PBControl or ioResult.
  457.  */
  458. OSErr LowUDPRelease (StreamPtr stream)
  459. {
  460.     UDPiopb pb;
  461.     OSErr err = noErr;
  462.  
  463.     InitUDPPB(&pb);
  464.     
  465.     pb.csCode = UDPRelease;
  466.     pb.udpStream = stream;
  467.  
  468.     if ((err = PBControl((ParmBlkPtr)&pb, true)) != noErr)
  469.         return err;
  470.     while (pb.ioResult >0) (*gSpin)();
  471.  
  472.     if (pb.ioResult != noErr) return pb.ioResult;
  473.     
  474.     DisposPtr(pb.csParam.create.rcvBuff);
  475.     return MemError();
  476. }
  477.  
  478. /* LowUDPMTU
  479.  * Divines the MTU for a given UDP stream.
  480.  *    stream     - the UDP stream ptr;
  481.  *    remoteHost - IP Number of the host one wants to send to;
  482.  *      *MTU         - returns the size of MTU in bytes.
  483.  * Returns OSErr: PBControl or ioResult.
  484.  */
  485. OSErr LowUDPMTU (StreamPtr stream, unsigned long remoteHost, unsigned short *MTU)
  486. {
  487.     UDPiopb pb;
  488.     OSErr err = noErr;
  489.  
  490.     InitUDPPB(&pb);
  491.     
  492.     pb.csCode = UDPMaxMTUSize;
  493.     pb.udpStream = stream;
  494.     pb.csParam.mtu.remoteHost = remoteHost;
  495.  
  496.     if ((err = PBControl((ParmBlkPtr)&pb, true)) != noErr)
  497.         return err;
  498.     while (pb.ioResult >0) 
  499.         if ((*gSpin)())
  500.             return 1;
  501.  
  502.     *MTU = pb.csParam.mtu.mtuSize;
  503.         
  504.     return (pb.ioResult);
  505.  
  506. }
  507.  
  508. /* multiport UDP commands have been ignored */
  509.  
  510.  
  511.  
  512.  
  513. /**
  514.  **
  515.  **  TCP/IP MacTCP ROUTINES
  516.  **
  517.  **/
  518.  
  519.  
  520. /* InitTCPPB
  521.  * - A utility routine to zero a TCPiopb structure, and set some
  522.  *     global initializations.
  523.  *        *pb - TCPiopb to be initialized
  524.  */
  525.  
  526. void InitTCPPB (TCPiopb *pb)
  527. {
  528.     bzero ((char *)pb, sizeof(TCPiopb));
  529.     pb->ioResult = 1;
  530.     pb->ioCRefNum = gRefNum;
  531. }
  532.     
  533.     
  534.  
  535. /* LowTCPCreate
  536.  * - Creates TCP stream asynchronously.
  537.  *     *stream - returns the TCP stream pointer.
  538.  *       *sockets- this is ip.c specific - an unfortunate kludge.
  539.  * Returns OSErr: MemErr and PBControl
  540.  */
  541.  
  542. OSErr LowTCPCreate (StreamPtr *stream, mac_socket *sockets)
  543. {    
  544.     TCPiopb pb;
  545.     OSErr err = noErr;
  546.     Ptr buffer;
  547. #ifdef __UNIVERSAL_HEADERS__
  548.     // here's a minor memory leak. If this socket is disposed, the notifyUPP won't
  549.     // be disposed.
  550.     TCPNotifyUPP notifyUPP = NewTCPNotifyProc(MyTCPNotifyProc);
  551. #endif // __UNIVERSAL_HEADERS__
  552.         
  553.     buffer = NewPtr(kBufferLength);
  554.     if ((err = MemError()) != noErr) {
  555.         return (err);
  556.     }
  557.     
  558.     InitTCPPB(&pb);
  559.     
  560.     pb.csCode = TCPCreate;
  561.     pb.csParam.create.rcvBuff = buffer;
  562.     pb.csParam.create.rcvBuffLen = kBufferLength;
  563. #ifdef __UNIVERSAL_HEADERS__
  564.     pb.csParam.create.notifyProc = notifyUPP;
  565. #else
  566.      pb.csParam.create.notifyProc = MyTCPNotifyProc;
  567. #endif // __UNIVERSAL_HEADERS__
  568.     pb.csParam.create.userDataPtr = (Ptr)sockets;
  569.     
  570.     err = PBControl((ParmBlkPtr)&pb,true);
  571.     if (err != noErr ) return err;
  572.     
  573.     while (pb.ioResult > 0) (*gSpin)();
  574.     *stream = pb.tcpStream;
  575.     
  576.     err = pb.ioResult;
  577.  
  578.     return err;
  579. }
  580.  
  581.  
  582. /* LowTCPPassiveOpen
  583.  * - waits on a stream for an incomming connection. This procedure
  584.  *   will block until a connection is received.
  585.  *      stream       - socket descriptor
  586.  *      char           - time out value in seconds
  587.  *      *remoteHost - registers the address connections may be received
  588.  *                    from. Passing 0 allows any address to connect. 
  589.  *                    Returns remoteHost IPNumber if 0 was passed to it.
  590.  *      *remotePort - as above for *remoteHost
  591.  *      *localhost  - returns local host IP
  592.  *      *localPort  - port to listen to; 0 specifies any port. Returns the
  593.  *                    port connected to.
  594.  * Returns OSErr: PBControl
  595.  */
  596. OSErr LowTCPPassiveOpen (StreamPtr stream, char timeout,
  597.     unsigned long *remoteHost, unsigned short *remotePort, unsigned long *localHost,
  598.     unsigned short *localPort)
  599. {
  600.     OSErr err = noErr;
  601.     TCPiopb pb;
  602.     
  603.     InitTCPPB(&pb);
  604.  
  605.     pb.csCode = TCPPassiveOpen;
  606.     pb.tcpStream = stream;
  607.     pb.csParam.open.ulpTimeoutValue = timeout;
  608.     pb.csParam.open.ulpTimeoutAction = 1;
  609.     pb.csParam.open.validityFlags = 0xC0;        /* timeout flags */
  610.     pb.csParam.open.commandTimeoutValue = timeout;
  611.     pb.csParam.open.remoteHost = *remoteHost;
  612.     pb.csParam.open.remotePort = *remotePort;
  613.     pb.csParam.open.localPort = *localPort;
  614.     
  615.     err = PBControl((ParmBlkPtr)&pb,true);
  616.     if (err != noErr) return err;
  617.     
  618.     while (pb.ioResult > 0 ) 
  619.         if ((*gSpin)())
  620.             return 1;
  621.  
  622.     err = pb.ioResult;
  623.     
  624.     *remoteHost = pb.csParam.open.remoteHost;
  625.     *remotePort = pb.csParam.open.remotePort;
  626.     return err;
  627. }
  628.  
  629.  
  630.  
  631.  
  632. /* LowTCPActiveOpen
  633.  * - Actively connects with a server on the specified remoteHost and
  634.  *     remotePort
  635.  *      stream       - socket descriptor
  636.  *      char           - time out value in seconds
  637.  *      remoteHost  - IPAddress unsigned long notation. (can't be 0)
  638.  *      remotePort  - port to connect to. (can't be 0)
  639.  *      *localhost  - returns local host IP
  640.  *      *localPort  - port to use; 0 specifies any port. Returns the
  641.  *                    port connected to.
  642.  * Returns OSErr: StrToAddr or PBControl
  643.  */
  644.  
  645. OSErr LowTCPActiveOpen (StreamPtr stream, char timeout,
  646.     unsigned long remoteHost, unsigned short remotePort, unsigned long *localHost,
  647.     unsigned short *localPort)
  648. {
  649.     OSErr err = noErr;
  650.     TCPiopb pb;
  651.                 
  652.     InitTCPPB(&pb);
  653.  
  654.     pb.csCode = TCPActiveOpen;
  655.     pb.tcpStream = stream;
  656.     pb.csParam.open.ulpTimeoutValue = timeout;
  657.     pb.csParam.open.ulpTimeoutAction = 1;
  658.     pb.csParam.open.validityFlags = 0xC0;        /* timeout flags */
  659.     pb.csParam.open.commandTimeoutValue = timeout;
  660.     pb.csParam.open.remoteHost = remoteHost;
  661.     pb.csParam.open.remotePort = remotePort;
  662.     pb.csParam.open.localPort = *localPort;
  663.     
  664.     err = PBControl((ParmBlkPtr)&pb,true);
  665.     if (err != noErr) return err;
  666.  
  667.     while (pb.ioResult > 0 )
  668.         if ((*gSpin)())
  669.             return 1;
  670.  
  671.     err = pb.ioResult;
  672.     *localPort = pb.csParam.open.localPort;
  673.     *localHost = pb.csParam.open.localHost;
  674.     return err;
  675. }
  676.  
  677.  
  678. /* LowTCPSend
  679.  * - Sends data over the stream
  680.  *    stream - stream descriptor
  681.  *    char   - time out in seconds
  682.  *    wdsPtr - write structure
  683.  * Returns OSErr: PBControl
  684.  */
  685. OSErr LowTCPSend (StreamPtr stream, char timeout, Ptr wdsPtr)
  686. {
  687.     OSErr err = noErr;
  688.     TCPiopb pb;
  689.     
  690.     InitTCPPB(&pb);
  691.  
  692.     pb.csCode = TCPSend;
  693.     pb.tcpStream = stream;
  694.     pb.csParam.send.ulpTimeoutValue = timeout;
  695.     pb.csParam.send.ulpTimeoutAction = 1;
  696.     pb.csParam.send.validityFlags = 0xC0;
  697.     pb.csParam.send.wdsPtr = wdsPtr;
  698.     
  699.     err = PBControl((ParmBlkPtr)&pb,true);
  700.     if (err != noErr) return err;
  701.     
  702.     while (pb.ioResult>0) 
  703.         if ((*gSpin)())
  704.             return 1;
  705.  
  706.     err = pb.ioResult;
  707.     return err;
  708. }
  709.  
  710. /* I'm going to ignore the NoCopy routines, because I don't understand them */
  711.  
  712.  
  713. /* LowTCPRcv
  714.  * - receives data over the stream
  715.  *    stream  - stream descriptor
  716.  *    char    - time out in seconds
  717.  *    rbuf      - memory buffer
  718.  *      *buflen - length of memory buffer. Returns # of bytes received.
  719.  * Returns OSErr: PBControl
  720.  */
  721. OSErr LowTCPRcv (StreamPtr stream, char timeout, Ptr rbuf, int *buflen)
  722. {
  723.     OSErr err = noErr;
  724.     TCPiopb pb;
  725.     
  726.     InitTCPPB(&pb);
  727.  
  728.     pb.csCode = TCPRcv;
  729.     pb.tcpStream = stream;
  730.     pb.csParam.receive.commandTimeoutValue = timeout;
  731.     pb.csParam.receive.rcvBuff = rbuf;
  732.     pb.csParam.receive.rcvBuffLen = *buflen;
  733.     
  734.     err = PBControl((ParmBlkPtr)&pb,true);
  735.     if (err != noErr) return err;
  736.     
  737.     while (pb.ioResult>0)
  738.         if ((*gSpin)())
  739.             return 1;
  740.  
  741.     *buflen = pb.csParam.receive.rcvBuffLen;
  742.     err = pb.ioResult;
  743.     
  744.     return err;
  745. }
  746.  
  747.  
  748. /* LowTCPClose
  749.  * - Closes a stream.
  750.  *      stream - stream descriptor
  751.  *      char     - timeout in seconds
  752.  * Returns OSErr: PBControl
  753.  */
  754.  
  755. OSErr LowTCPClose (StreamPtr stream, char timeout)
  756. {
  757.     OSErr err = noErr;
  758.     TCPiopb pb;
  759.     
  760.     InitTCPPB(&pb);
  761.  
  762.     pb.csCode = TCPClose;
  763.     pb.tcpStream = stream;
  764.     pb.csParam.close.ulpTimeoutValue = timeout;
  765.     pb.csParam.close.ulpTimeoutAction = 1;
  766.     pb.csParam.close.validityFlags = 0xC0;
  767.     
  768.     err = PBControl((ParmBlkPtr)&pb,true);
  769.     if (err != noErr) return err;
  770.     
  771.     while (pb.ioResult>0) (*gSpin)();
  772.  
  773.     err = pb.ioResult;
  774.     
  775.     return err;
  776. }
  777.  
  778.  
  779. /* LowTCPAbort
  780.  * - Abruptly closes a stream.
  781.  *      stream - stream descriptor
  782.  * Returns OSErr: PBControl
  783.  */
  784.  
  785. OSErr LowTCPAbort(StreamPtr stream)
  786. {
  787.     OSErr err = noErr;
  788.     TCPiopb pb;
  789.     
  790.     InitTCPPB(&pb);
  791.  
  792.     pb.csCode = TCPAbort;
  793.     pb.tcpStream = stream;
  794.     
  795.     err = PBControl((ParmBlkPtr)&pb,true);
  796.     if (err != noErr) return err;
  797.     
  798.     while (pb.ioResult>0) (*gSpin)();
  799.  
  800.     err = pb.ioResult;
  801.     
  802.     return err;
  803. }
  804.  
  805. /* LowTCPStatus 
  806.  * Entire routine written 8/28/95 - MDT (version 1.1)
  807.  * - Returns a TCPStatusPB for the given stream pointer.
  808.  *    stream    - stream descriptor
  809.  *    *statusPB - address of a valid status parameter block
  810.  * Returns OSErr: PBControl
  811.  */
  812. OSErr LowTCPStatus(StreamPtr stream, TCPStatusPB *statusPB )
  813. {
  814.     OSErr err = noErr;
  815.     TCPiopb pb;
  816.     
  817.     InitTCPPB(&pb);
  818.  
  819.     pb.csCode = TCPStatus;
  820.     pb.tcpStream = stream;
  821.     
  822.     err = PBControl((ParmBlkPtr)&pb,true);
  823.     if (err != noErr) return err;
  824.     
  825.     while (pb.ioResult>0) (*gSpin)();
  826.  
  827.     err = pb.ioResult;
  828.     
  829.     if (err == noErr) {
  830.         *statusPB = pb.csParam.status;
  831.     }
  832.     
  833.     return err;
  834. }
  835.  
  836.  
  837. /* LowTCPRelease
  838.  * - Releases memory reserved for a stream. If the stream is still
  839.  *      connected, the stream will be aborted.
  840.  *      stream - stream descriptor
  841.  * Returns OSErr: PBControl and MemError
  842.  */
  843.  
  844. OSErr LowTCPRelease(StreamPtr stream)
  845. {
  846.     OSErr err = noErr;
  847.     TCPiopb pb;
  848.     Ptr buffer;
  849.     
  850.     InitTCPPB(&pb);
  851.  
  852.     pb.csCode = TCPRelease;
  853.     pb.tcpStream = stream;
  854.     
  855.     err = PBControl((ParmBlkPtr)&pb,true);
  856.     if (err != noErr) return err;
  857.     
  858.     while (pb.ioResult>0) (*gSpin)();
  859.  
  860.     if ((err = pb.ioResult) != noErr) return err;
  861.     buffer = pb.csParam.create.rcvBuff;
  862.  
  863.     DisposPtr(buffer);
  864.     err = MemError();
  865.     return err;
  866. }
  867.  
  868. /* LowGlobalInfo - skip */
  869.  
  870.  
  871.  
  872.  
  873. /* LowTCPSelect
  874.  * - Reports if there is unread data on a stream.
  875.  *        stream - stream descriptor
  876.  *        *ans   - 0 if no data waiting , 1 if data waiting.
  877.  * Returns OSErr: PBControl
  878.  */
  879.  
  880. /* OBSOLETE - Moved to a higher level because of ASR */
  881.  
  882. OSErr LowTCPSelect (StreamPtr stream, int *ans)
  883. {
  884.     OSErr err;
  885.     TCPiopb pb;
  886.     
  887.     InitTCPPB(&pb);
  888.  
  889.     pb.csCode = TCPStatus;
  890.     pb.tcpStream = stream;
  891.     
  892.     err = PBControl((ParmBlkPtr)&pb,true);
  893.     if (err != noErr) return err;
  894.     
  895.     while (pb.ioResult>0)
  896.         if ((*gSpin)())
  897.             return 1;
  898.  
  899.     err = pb.ioResult;
  900.  
  901.     if (pb.csParam.status.amtUnreadData > 0) {
  902.         *ans = 1;
  903.     } else {
  904.         *ans = 0;
  905.     }
  906.     
  907.     return err;
  908. }
  909.  
  910. /* The following code is specifically for my socket ip.c file.  They are two 
  911.  * MacTCP call back routines necessary to provide select() support.  I'm still
  912.  * finding bugs in these routines - I think I was sleepy when I wrote them.
  913.  * Handle with care - MDT.
  914.  */
  915.  
  916. pascal void MyUDPNotifyProc(StreamPtr stream, unsigned short eventCode, Ptr data, 
  917.                             struct ICMPReport *icmpMsg)
  918. {
  919. #pragma unused (icmpMsg)
  920.     short i,s = -1;
  921.     
  922.     for (i=0; i<kNumSockets; i++){
  923.         if (((mac_socket *) data)[i].stream == stream){
  924.             s = i;
  925.             break;
  926.         }
  927.     }
  928.     if (s < 0) return;
  929.  
  930.     switch (eventCode) {
  931.     case UDPDataArrival:
  932.         ((mac_socket *)data)[s].hasData = 1;
  933.         break;
  934.     default:
  935.         ;
  936.     }
  937. }
  938.  
  939. pascal void MyTCPNotifyProc(StreamPtr stream, unsigned short eventCode, Ptr data, 
  940.                             unsigned short termr, struct ICMPReport *icmpMsg)
  941. {
  942. #pragma unused (icmpMsg)
  943. #pragma unused (termr)
  944.     short i,s = -1;
  945.     
  946.     for (i=0; i<kNumSockets; i++){
  947.         if (((mac_socket *) data)[i].stream == stream) {
  948.             s = i;
  949.             break;
  950.         }
  951.     }
  952.     if (s < 0) return;
  953.  
  954.     switch (eventCode) {
  955.     case TCPDataArrival:
  956.         ((mac_socket *)data)[s].hasData = 1;
  957.         break;
  958.     default:
  959.         ;
  960.     }
  961. }